home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / lack.zoo / trap2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-01  |  15.8 KB  |  592 lines

  1. #include "lack.h"
  2. #include "sysvars.h"
  3. #include "xbra.h"
  4. #include <string.h>
  5. #include <osbind.h>
  6. #include <mintbind.h>
  7.  
  8. lap *lapps[NUM_APPS];
  9. lap *curapp;
  10.  
  11. struct save_area
  12. {
  13.     int in_use;
  14.     long dregs[8];     /* These are gem's registers at the time of the
  15.                 * task switch.  User's registers are pushed onto
  16.                 * the usp. */
  17.     void (*stopped)(); /* Where the task switch was called from. */
  18.     long aregs[6];     /* a1-a6 as dregs */
  19.     void *g_ssp;       /* + 0x3e */
  20.     void *usp;       /* + 0x42 */
  21.     void *u_ssp;       /* + 0x46 */
  22. };
  23.  
  24. ki;
  25.  
  26. int in_aes;    /* are we servicing an aes call, rather than letting some apid run */
  27. int get_menu_title; /* let the controler acc's do menu_register? */
  28. int aes_active;     /* I don't know how to keep this thing up to date */
  29. int aes_version;
  30. struct save_area *apid0_save=NULL; /* test for wether apid 0 is the desktop, see below */
  31. struct appl *apid0_appl;      /*  "    "    " ...                                 */
  32. int is_desk=FALSE;
  33. static int first=TRUE;
  34. int apid;      /* the running application, to the best of my knowledge */
  35. int __desk_stk[1024];
  36. const long desk_stk=(long)&__desk_stk[1023];
  37. static void (*yield_aes)(void);
  38. void *os_base;
  39. /*void *os_end; I don't know how to set this */
  40.  
  41. struct global_action *gl_action;
  42.  
  43. /* in lack.s: */
  44. extern void trap_2(void);
  45. extern void trap_3(void);
  46. extern void trap_13(void);
  47. extern void _first_leave_aes(void);
  48. extern void _desk_leave_aes(void);
  49.  
  50. /* in jump.s: */
  51. extern int setjump(lap *);
  52. extern int longjump(lap *);
  53.  
  54. /* in wind.c: */
  55. extern void desk_zap_windows(void);
  56.  
  57. /* vectors to search down before unloading acc, the first nine spaces are for
  58.  * kbdvecs.
  59.  * Maybe I should add mfp ints, or save everything which doesn't have the high
  60.  * byte set.  It does not take much memory to save these things and refer back
  61.  * to them.
  62.  * If you add vectors leave off the cast, and the error message will tell you
  63.  * what NUM_VECS should be changed to.
  64.  */
  65. #define NUM_VECS 54
  66. char **vecs[NUM_VECS]={(char **)0x0, (char **)0x0, (char **)0x0, (char **)0x0, 
  67. (char **)0x0, (char **)0x0, (char **)0x0, (char **)0x0, (char **)0x0, 
  68. (char **)0x08, (char **)0x0c, (char **)0x10, (char **)0x14, (char **)0x18, 
  69. (char **)0x1c, (char **)0x20, (char **)0x24, (char **)0x2c, (char **)0x34, 
  70. (char **)0x38, (char **)0x3c, (char **)0x60, (char **)0x70, (char **)0x84, 
  71. (char **)0x88, (char **)0xb4, (char **)0xb8, (char **)0xc0, (char **)0xe0, 
  72. (char **)0xe4, (char **)0xe8, (char **)0x114, (char **)0x400, (char **)0x404, 
  73. (char **)0x408, (char **)0x42a, (char **)0x472, (char **)0x476, (char **)0x47e, 
  74. (char **)0x4f6, (char **)0x506, (char **)0x50a, (char **)0x50e, (char **)0x512, 
  75. (char **)0x51e, (char **)0x53e, (char **)0x55e, (char **)0x57e, (char **)0x108, 
  76. (char **)0x118, (char **)0x124, (char **)0x128, (char **)0x12c, (char **)0x130};
  77.  
  78. struct xbra gem=  {XBRA_MAGIC, 0x6c61636bL /*'lack'*/, NULL, JMP_OPCODE,
  79.            (void *)trap_2};
  80. struct xbra mytrap={XBRA_MAGIC, 0x6c61636bL /*'lack'*/, NULL, JMP_OPCODE,
  81.            (void *)trap_3};
  82. struct xbra bios= {XBRA_MAGIC, 0x6c61636bL /*'lack'*/, NULL, JMP_OPCODE,
  83.            (void *)trap_13};
  84. install_trap2()
  85. {
  86.     long ssp;
  87.     int sr;
  88.     char *sp;
  89.     char **kvecs;
  90.     int c;
  91.  
  92.     kvecs=(char **)Kbdvbase(); /* this assumes Kbdbase returns the a pointer
  93.                                 * to the actual vectors */
  94.     for(c=0; c<9; c++)
  95.         vecs[c]=kvecs++;
  96.     ssp=Super(0);
  97.     sr=spl7();
  98.     os_base=(*_sysbase)->os_beg;
  99.     gem.xb_old=*(void **)0x88L;
  100.     *(short **)0x88L=&gem.xb_op;
  101.     mytrap.xb_old=*(void **)0x8cL;
  102.     *(short **)0x8cL=&mytrap.xb_op;
  103.     bios.xb_old=*(void **)0xb4L;
  104.     *(short **)0xb4L=&bios.xb_op;
  105.     /* find apid0_appl */
  106.     apid0_appl=aes_appl;
  107.     while(apid0_appl->apid!=0 && apid0_appl->next)
  108.         apid0_appl=apid0_appl->next;
  109.     if(apid0_appl->apid!=0)
  110.     {
  111.          ALERT("could not find apid 0");
  112.          apid0_appl=NULL;
  113.     }else{
  114.          DEBUG("apid 0 application structure at %lx", apid0_appl);
  115.          apid0_save=(struct save_area *)apid0_appl->save_area;
  116.          yield_aes=*(((void(**)())apid0_save->g_ssp) - 1);
  117.     }
  118.     lapps[0]->istk=desk_stk;
  119.     if(!strncmp (apid0_appl->name, "        ", 8))
  120.     {
  121.         /* at startup, anything will look like the desktop */
  122.         DEBUG("lack: apid 0 is desktop");
  123.         is_desk=TRUE;
  124.         sp=(char *)apid0_save->g_ssp;
  125.         if(*sp==0 || *longframe)
  126.         /* if it isn't a 030, it can't have an address with the top
  127.          * byte set, so this test for linef works */
  128.         {
  129.             lapps[0]->pc=*(void(**))sp;
  130.             *(void(**))sp=_desk_leave_aes;
  131.             aes_version=0x160;  /* will be reset by lackcontrol's appl_init */
  132.             DEBUG("tos >= 1.6");
  133.         }else{
  134.         lapps[0]->pc=*(void(**))(sp + 2);
  135.         *(void(**))(sp + 2)=_desk_leave_aes;
  136.             aes_version=0x140;  /* will be reset by lackcontrol's appl_init */
  137.         DEBUG("tos < 1.6");
  138.         }
  139.     }else{
  140.         DEBUG("lack: apid 0 is not desktop");
  141.         first=TRUE;
  142.         sp=(char *)apid0_save->u_ssp;
  143.         if(*longframe)
  144.         {
  145.             lapps[0]->pc=*(void(**))(sp + 4);
  146.             *(void (**))(sp + 4)=_first_leave_aes;
  147.         }else{
  148.             lapps[0]->pc=*(void(**))(sp + 2);
  149.             *(void(**))(sp + 2)=_first_leave_aes;
  150.         }
  151.         lapps[0]->in_aes=1;
  152.     }DEBUG("changing pc %lx on stack %lx", lapps[0]->pc, sp);
  153.     spl(sr);
  154.     Super(ssp);
  155. }
  156.  
  157. void
  158. get_gem_stack()
  159. {
  160.     /* acc user and gem ssp's are on the same stack.  The acc needs to
  161.      * return from Dcntl(LA_INIT_ACC) while it's gem stack is in use.
  162.      * So, we change the gem stack so the acc's ssp can be used for
  163.      * Dcntl(LA_WAKE_APP) when it is time to return to the caller pid.
  164.      * For the first acc, it needs to call Dcntl(LA_WAKE_APP) when gem
  165.      * pid 0 is running, but MiNT lackontrol proccess is active, that
  166.      * is, when apid 0 returns from the trap 2 call made by lackontrol.
  167.      * I hope this makes some sense.
  168.      */
  169.     struct save_area *my_save;
  170.     char *my_gem_stack;
  171.     long ssp; int sr;
  172.  
  173.     my_gem_stack=(char *)Mxalloc(4096, M_PROT_S | M_ALT);
  174.     curapp->mystk_base = curapp->mystk = (long)my_gem_stack+4096;
  175.     my_gem_stack+=2048;
  176.     ssp=Super(0);
  177.     sr=spl7();
  178.     my_save=aes_appl->save_area;
  179.     DEBUG("changing gem's ssp from %lx to %lx", my_save->g_ssp, my_gem_stack);
  180.     my_save->g_ssp=my_gem_stack;
  181.     spl(sr);
  182.     Super(ssp);
  183. }
  184.  
  185. int
  186. check_for_desk(int was_desk)
  187. {
  188.     char *sp;
  189.     
  190.     if(!strncmp(apid0_appl->name, "        ", 8))
  191.     {
  192.     /* Make sure apid 0 is still the desktop */
  193.         sp=(char *)apid0_save->g_ssp;
  194.         if(aes_version > 0x140) /* notice that this differs from the rom rev */
  195.         {
  196.         /* save the pc of desktop and make it return to me, so I can 
  197.          * adjust the MiNT pid, etc.  I figure the desktop call the
  198.          * aes function dipatcher via line-f or jsr, (depending on wether
  199.          * there is such a thing as line-f).
  200.          */
  201.           if (*(void(**))sp!=_desk_leave_aes)
  202.           {
  203.             lapps[0]->pc=*(void(**))sp;
  204.             *(void(**))sp=_desk_leave_aes;
  205.             DEBUG("changed pc %lx on stack %lx", lapps[0]->pc, sp);
  206.           }
  207.         }else{
  208.           if(*(void(**))((char *)sp+2)!=_desk_leave_aes)
  209.           {
  210.         lapps[0]->pc=*(void(**))((char *)sp+2);
  211.         *(void(**))((char *)sp+2)=_desk_leave_aes;
  212.         DEBUG("changed pc %lx on stack %lx", lapps[0]->pc, sp);
  213.           }
  214.         }
  215.         lapps[0]->in_aes=1;
  216.         if (!was_desk) lapps[0]->istk=desk_stk;
  217.     }else{
  218.         is_desk=FALSE;
  219.         if(was_desk) /* desktop has done wind_new */ desk_zap_windows();
  220.         else /* an application has exited, but the desktop didn't
  221.           * wake up. */
  222.          DEBUG("not desktop");
  223.     }
  224. }
  225.  
  226. void
  227. print_global(AESP *call)
  228. {
  229.     char line[80];
  230.     int last=0;
  231.     int count, *global=call->global;
  232.  
  233.     DEBUG("global array from call %d", call->control[0]);
  234.     for(count=0; count<15; count++)
  235.     {
  236.         ksprintf(&line[last], "%x, ", global[count]);
  237.         last=strlen(line);
  238.         if(last>73)
  239.         {
  240.             DEBUG(line);
  241.             last=0;
  242.         }
  243.     }
  244.     if(last) DEBUG(line);
  245. }
  246.  
  247. int
  248. unload()
  249. {
  250.     /* this is called by handle_action during entry to or exit from aes */
  251.     /* we certainly are putting alot of stuff on someone else's stack */
  252.     AESP *old=_aesparams;
  253.     int (*oldcall)()=__aes__;
  254.     NEW_AESP(a);
  255.     BASEPAGE *b=curapp->acc->base;
  256.     char *start=b->p_tbase;
  257.     char *end=start + b->p_tlen + b->p_dlen + b->p_blen;
  258.     char *cur;
  259.     char **prev=vecs[0];
  260.     struct xbra *x;
  261.     int c, sr, fail=0;
  262.     char error_mess[90];
  263.  
  264.     DEBUG("unloading %s from apid %d", curapp->acc->name, apid);
  265.     _aesparams=&a;
  266.     a.global=old->global;
  267.     __aes__=_super_aes;
  268.     sr=spl7();
  269.     /*all breaks but the last one: "if(fail)" break out of the while loop*/
  270.     for(c=0; c<NUM_VECS; prev=vecs[++c])
  271.     {
  272.       while(1)
  273.       {
  274.           cur=*prev;
  275.              if(!cur) break; /* this is for _shell_p */
  276.           if(IS_XBRA(cur))
  277.           {
  278.               x=XBRA(cur);
  279.               if(cur>start && cur < end)
  280.             {
  281.                 *prev=x->xb_old;
  282.                 DEBUG("lack: unchaining from vector %lx", vecs[c]);
  283.                 break;
  284.             }
  285.               else if (XB_IS_JUMP(x))
  286.               {
  287.                   if((char *)x->xb_func > start &&
  288.                    (char *)x->xb_func < end)
  289.                   {
  290.                       *prev=x->xb_old;
  291.                     DEBUG("lack: unchaining from vector %lx",
  292.                       vecs[c]);
  293.                       break;
  294.                   }
  295.               }
  296.               prev=(char **)&x->xb_old;
  297.           }else{
  298.               if(cur>start && cur<end)
  299.               {
  300.                   fail=TRUE;
  301.                   ksprintf(error_mess,"[1][lack: could not unhook %s|from vector 0x%lx][ worthless program ]",
  302.                        curapp->acc->name, vecs[c]);
  303.               }
  304.               break;
  305.           }
  306.       }
  307.       if (fail) break;
  308.     }
  309.     spl(sr);
  310.     if(fail)
  311.     {
  312.         form_alert(3, error_mess);
  313.         _aesparams=old;
  314.         __aes__=oldcall;
  315.         return -1;
  316.     }
  317.     Wind_new(&a);
  318.     rsrc_free();
  319.     _aesparams=old;
  320.     __aes__=oldcall;
  321.     curapp->in_aes=0;
  322.     in_aes=FALSE;
  323.     curapp->mystk=curapp->mystk_base;
  324.     Pterm(0);
  325. }
  326.  
  327. void
  328. handle_action()
  329. {
  330.     int *todo=&curapp->action;
  331.  
  332.     switch(*todo)
  333.     {
  334.         case APPL_ALIVE:
  335.             aes_active=TRUE;
  336.             break;
  337.         case APPL_KILL:
  338.             *todo=0; /* unload will make aes calls, and do Pterm */
  339.             unload();/* if it succeeds. */
  340.             break;
  341.         case APPL_INIT:
  342.             if (aes_version<0x140)
  343.                 curapp->call->global[0]=0x140;
  344.             curapp->call->global[1]=NUM_APPS;
  345.             break;
  346.         case WIND_CREATE:
  347.             Wind_create(curapp->call);
  348.             break;
  349.         case RSRC_LOAD:
  350.             print_global(curapp->call);
  351.         default:
  352.     }
  353.     *todo=0;
  354. }
  355.  
  356. void
  357. handle_gl_action()
  358. {
  359.     struct global_action *this=gl_action;
  360.     AESP *old=_aesparams;
  361.     int (*oldcall)()=__aes__;
  362.     NEW_AESP(a);
  363.     int mess[8]={LA_KILL_ACC, apid, 0};
  364.     int sr;
  365.  
  366.     _aesparams=&a;
  367.     __aes__=_super_aes;
  368.     a.global=curapp->call->global;
  369.     while(this)
  370.     {
  371.         gl_action=this->next;
  372.         if(lapps[this->apid]->action==APPL_KILL)
  373.         {
  374.             DEBUG("sending kill message to apid %d", this->apid);
  375.             appl_write(this->apid, 16, mess);
  376.         }
  377.         sr=spl7();
  378.         kfree(this);
  379.         spl(sr);
  380.         this=gl_action;
  381.     }
  382.     _aesparams=old;
  383.     __aes__=oldcall;
  384. }
  385.  
  386. void *
  387. leave_aes()
  388. {
  389.     lap *a=lapps[cur_apid];
  390.  
  391.     if(apid != cur_apid)
  392.     {
  393.         if(!setjump(a))
  394.         /* save this jump context for the current apid */
  395.         {
  396.             Dcntl(LA_WAKE_APP, "S:", a);
  397.             /* wake up its corresponding processes */
  398.             longjump(lapps[cur_apid]);
  399.             /* always longjump upon waking */
  400.         }
  401.         apid=cur_apid;
  402.         curapp=lapps[apid];
  403.     }
  404.     if(gl_action) handle_gl_action();
  405.     if(curapp->action) handle_action();
  406.     in_aes=FALSE;    /* now what about my aes emulation call? */
  407.     curapp->in_aes-=1;
  408.     if(apid==0)
  409.     {
  410.         if(is_desk || first)
  411.         /* _desk_leave_aes intercepts the desktop as gem wakes it up,
  412.          * leave_aes() will set mystk to the desktop's stack, when a
  413.          * program is launched, we want mystk to be set to desk_stk.
  414.          */
  415.         {
  416.             if (first) first=FALSE;
  417.             curapp->mystk=desk_stk;
  418.         return(curapp->pc);
  419.         }
  420.  
  421.     }
  422.     return NULL;
  423. }
  424.  
  425. /* Returns 0 if this call should be passed to the aes, otherwise returns 1.
  426.  * When aes calls are made from within enter_aes or leave_aes, they are sent
  427.  * directly to gem. */
  428. int
  429. enter_aes(AESP *call, void(**pc)())
  430. {
  431.     int cmd, done=0;
  432.     
  433.     if(gl_action) handle_gl_action();
  434.     if(apid != cur_apid)
  435.     {
  436.         ALERT("lack: I thought this was apid %d, but gem says it is %d",
  437.               apid, cur_apid);
  438.         apid=cur_apid;
  439.     }
  440.     curapp->call=call;
  441.     curapp->in_aes+=1;
  442.     if(curapp->action)
  443.         handle_action();
  444.     cmd=call->control[0];
  445.     /* The action APPL_KILL sets control[0] to APPL_KILL in order to force 
  446.      * immediate return from the aes call.
  447.      */
  448.     TRACE("apid %d calling aes command %d", apid, cmd);
  449.     if (curapp->in_aes==1) curapp->pc=(void(*)())pc;
  450.     /* If we think it is the desktop, we check that the aes agrees, then we
  451.      * make sure it is set up to return from aes calls through us.  If is_desk
  452.      * but it isn't the desktop, we make is_desk false, and wait for trap_13
  453.      * to change it (when the desktop returns, it resets the trap 2 vector
  454.      * then does Setexec(101,...)).
  455.      */
  456.     if(is_desk) check_for_desk(TRUE);
  457.     if(curapp->in_aes>1)
  458.         DEBUG("lack: recursive call %d", cmd);
  459.     switch(cmd)
  460.     {
  461.         case APPL_KILL:
  462.             done=1; break; /* why is this here? */
  463.         case APPL_INIT:
  464.             curapp->action=APPL_INIT;
  465.             break;
  466.         case APPL_YIELD:
  467.             if (aes_version < 0x200)
  468.             {
  469.                 char *ssp=aes_appl->save_area->g_ssp;
  470.  
  471.                 DEBUG("lack: faking appl_yield");
  472.                 if(apid <= 0x140)
  473.                     asm(" .short 0xf084":::
  474.                     "d0", "d1", "d2", "a0", "a1", "a2");
  475.                 else asm(" jsr _yield_aes":::
  476.                      "d0", "d1", "d2", "a0", "a1", "a2");
  477.                 aes_appl->save_area->g_ssp=ssp;
  478.                 leave_aes();
  479.                 done=1;
  480.             }
  481.             break;
  482.         case APPL_EXIT:
  483.             if(apid!=0)
  484.             {
  485.                 DEBUG("catching appl_exit from apid %d", apid);
  486.                 done=1;
  487.             }
  488.             break;
  489.         case MENU_REGISTER:
  490.             if(get_menu_title) break;
  491.             DEBUG("lack: faking menu register");
  492.             strncpy(curapp->acc->menu_title, call->addr_in[0], 22);
  493.             call->int_out[0]=curapp->acc->menu_index;
  494.             done=1; break;
  495.         case MENU_UNREGISTER:
  496.             Menu_unregister();
  497.             done=1; break;
  498.         case MENU_BAR:
  499.             if(apid!=0)
  500.             {
  501.                 DEBUG("ignoring menu_bar from apid %d", apid);
  502.                 done=1;
  503.             }else{
  504.                 DEBUG("menu_bar(%d, %lx)", call->int_in[0],
  505.                       call->addr_in[0]);
  506.                 print_global(call);
  507.                 curapp->action=RSRC_LOAD;
  508.             }
  509.             break;
  510.         case RSRC_LOAD:
  511.             DEBUG("rscr_load(%s)", call->addr_in[0]);
  512.         case RSRC_FREE:
  513.             print_global(call);
  514.             curapp->action=RSRC_LOAD;
  515.             break;
  516.         case SHEL_FIND:
  517.             DEBUG("shel_find(%s)", call->addr_in[0]);
  518.             break;
  519. /*        case FSEL_INPUT:
  520.         case FSEL_XINPUT:*/
  521.     /* I should always keep track of these things, so that I can fake topped and
  522.      * untopped messages, and top all windows of a program running as an acc.
  523.      * To work with programs I've got to do my own wind_new, this will
  524.      * always cause problems with the desktop
  525.      */
  526.         case WIND_CREATE:
  527.             curapp->action=WIND_CREATE;
  528.             break;
  529.         case WIND_DELETE:
  530.             done=Wind_delete(call);
  531.             break;
  532.         case WIND_OPEN:
  533.             done=Wind_open(call);
  534.             break;
  535.         case WIND_CLOSE:
  536.             done=Wind_close(call);
  537.             break;
  538.         case WIND_UPDATE:
  539.             done=Wind_update(call);
  540.             break;
  541.         case WIND_NEW:
  542.             done=Wind_new(call);
  543.             break;
  544.     }
  545.     in_aes=!done;
  546.     if(done) curapp->in_aes-=1;
  547.     return done;
  548. }
  549.  
  550. int _super_aes(unsigned long coded_control)
  551. {
  552.  
  553.     curapp->in_aes+=1;
  554.     /* call aes */
  555.     __asm__ volatile
  556.     ("  movel    %1,  d1
  557.         moval    %0@, a0
  558.     moveq    #0,  d0
  559.     movepl    d0,  a0@(0)    | clear high bytes of control array
  560.         movepl    d1,  a0@(1)
  561.         movl    %0,   d1
  562.         movw    #0xc8,d0    | note -- no movq here, it sign extends
  563.     pea   pc@(2f)         |where trap #2 will return
  564.     tstw  0x59e          |longframe?
  565.     beqs  1f
  566.     clrw  sp@-
  567. 1:    movw  sr, sp@-
  568.     movl  _gem+8, sp@-
  569.     rts
  570.     tas     _use_trap_3
  571.     trap    #3
  572. 2:    movl    %0,   __aesparams"
  573.      :                /* no outputs */
  574.      : "a"(_aesparams), "g"(coded_control), "a"(__aes__)  /* inputs     */
  575.      : "d0", "d1", "a0"   /* clobbered regs */
  576.      );
  577.     __aes__=&_super_aes;
  578.     leave_aes();
  579.     return (int)_int_out[0];
  580. }
  581.  
  582. Menu_unregister()
  583. {
  584.     char *title=curapp->acc->menu_title;
  585.  
  586.     DEBUG("lack: faking menu unregister");
  587.     strcpy(title, "  "); title+=2;
  588.     strcpy(title, curapp->acc->name); title+=8;
  589.     strcpy(title, " <blank>   ");
  590. }
  591.  
  592.